home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1997 April / EnigmA AMIGA RUN 17 (1997)(G.R. Edizioni)(IT)[!][issue 1997-04][EAR-CD].iso / EARCD / comm / amiex / KLR_ChatSRC.lha / Chat-O-Top / Chat-O-Top.C < prev    next >
C/C++ Source or Header  |  1996-09-14  |  20KB  |  679 lines

  1. /*************************************************************************
  2.  
  3.                                 CHAT-O-TOP
  4.  
  5.          Small utility that is able to generate bulletins based up
  6.               a data file that is created with CHAT-O-METER.
  7.  
  8.                        (c) 1995 by KiLLraVeN/MYSTiC
  9.  
  10.  *************************************************************************
  11.  
  12.              This source can be compiled with NO startup-code!
  13.  
  14.                   Last Revision: Fri Jun 23 14:09:10 1995
  15.  
  16.  *************************************************************************/
  17.  
  18. #define CHAT_O_TOP
  19.  
  20. #include <exec/types.h>
  21. #include <exec/lists.h>
  22. #include <exec/memory.h>
  23.  
  24. #include <stdio.h>
  25. #include <string.h>
  26.  
  27. #include <clib/exec_protos.h>
  28. #include <clib/dos_protos.h>
  29.  
  30. #include <pragmas/exec_pragmas.h>
  31. #include <pragmas/dos_pragmas.h>
  32.  
  33. struct CHATTOP
  34. {
  35.     ULONG    Time;                        /* Total chat time            */
  36.     ULONG    Chats;                    /* Total number of chats    */
  37. };
  38.  
  39. struct USERTOP
  40. {
  41.     struct     Node    ut_Node;                /* For structure reference */
  42.     char        ut_Name[ 32 ];                /* Name of user                 */
  43.     char        ut_Location[ 31 ];        /* Location of user            */
  44.     ULONG        ut_Time;                        /* Chat time of user            */
  45.     ULONG        ut_Chats;                    /* Number of chats            */
  46.     ULONG        ut_Avg;                        /* Average time/chat            */
  47. };
  48.  
  49. struct USER
  50. {
  51.    char    Name[31],Pass[9],Location[30],PhoneNumber[13];
  52.    USHORT  Slot_Number;
  53.    USHORT  Sec_Status, RatioType, Ratio, CompType, Messages_Posted;
  54.    ULONG   NewSinceDate, CRCPassword, ConfRead2, ConfRead3;
  55.    UWORD   vote_yesno;
  56.    UWORD   voted;
  57.    UWORD   reserved;
  58.    UWORD   Area;
  59.    UWORD   XferProtocol, Filler2;
  60.    UWORD   Lcfiles, BadFiles;
  61.    ULONG   AccountDate;
  62.    UWORD   ScreenType, EditorType;
  63.    char    Conference_Access[10];
  64.    USHORT  Uploads, Downloads, ConfRJoin, Times_Called;
  65.    long    Time_Last_On, Time_Used, Time_Limit, Time_Total;
  66.    ULONG   Bytes_Download, Bytes_Upload, Daily_Bytes_Limit, Daily_Bytes_Dld;
  67.    char    Expert;
  68.    /* Note ConfYM = the last msg you actually read, ConfRead is the same ?? */
  69.    ULONG   ConfYM1, ConfYM2, ConfYM3, ConfYM4, ConfYM5, ConfYM6, ConfYM7,
  70.            ConfYM8, ConfYM9;
  71.    long    BeginLogCall;
  72.    UBYTE   Protocol, UUCPA, LineLength, New_User;
  73. };
  74.  
  75. #define    TEMPLATE        "TO,FROM,H=HEADER/K,UD=USERDATA/K,B=BORDER/K,TOP/K/N,SORT/K/N,MIN=MINIMUM/K/N,NO_HEADER/S,NO_CLS/S,REVERSED/S"
  76. #define    TEMPLATE_SIZE (11)
  77.  
  78. #define    TO_FILE    (0)
  79. #define    DATAFILE (1)
  80. #define    HEADER    (2)
  81. #define    USERDATA (3)
  82. #define    BORDER    (4)
  83. #define    TOP        (5)
  84. #define    SORT        (6)
  85. #define    MIN        (7)
  86. #define    NO_HEAD    (8)
  87. #define    NO_CLS    (9)
  88. #define    REVERSED    (10)
  89.  
  90. VOID  FreeNodes (struct List *);
  91. VOID  MyExit( struct Library *, struct USER *, struct CHATTOP *, struct RDArgs *, struct List *, int );
  92. VOID  myprintf( char * , char *, ...);
  93. ULONG GetFileSize( struct Library * , char * );
  94. VOID    PutInSortedList( struct List * , struct USERTOP * , ULONG , ULONG );
  95. BOOL    MeetMinimum( struct USERTOP * , ULONG , ULONG );
  96.  
  97. char    VER[] = "$VER: Chat-O-Top 1.0.5 BETA!"__AMIGADATE__;
  98.  
  99. VOID main ( int argc , char *argv[] )
  100. {
  101.     struct    Library *DOSBase = OpenLibrary( "dos.library" , 37L );
  102.  
  103.     BPTR        fh;
  104.  
  105.     char        *buffer,
  106.                 temp[ 400 ];
  107.  
  108.     struct    MinList    ut_List;
  109.     struct    USERTOP    *ut_Node, *ut_Worknode, *ut_Nextnode;
  110.     struct    USER        *user_ptr, *userdata = NULL;
  111.     struct    CHATTOP    *ct_ptr = NULL;
  112.  
  113.     struct     RDArgs    *rdargs;
  114.  
  115.     LONG defaults[ TEMPLATE_SIZE ] =
  116.     {
  117.         (LONG) "*",
  118.         (LONG) "PROGDIR:Chat-O-Top.Data",
  119.         (LONG) "PROGDIR:Chat-O-Top.Header",
  120.         (LONG) "BBS:User.Data",
  121.         (LONG) "",
  122.         (LONG) NULL,
  123.         (LONG) NULL,            /* Sort by Time */
  124.         (LONG) NULL,
  125.         (LONG) NULL
  126.     };
  127.  
  128.     int    zeros[] = { 67 , 71 , 93 , 96 , 104 , 107 , 137 , 141 };
  129.  
  130.     STRPTR headers[] = { " %s.--- --- -- -  -    cHAT-O-tOP uSER sTATiSTiCS bY tIME     %s-  - -- --- ---.\n |C|\n",
  131.                                " %s.--- --- -- -  -    cHAT-O-tOP uSER sTATiSTiCS bY cHATS    %s-  - -- --- ---.\n |C|\n",
  132.                                " %s.--- --- -- -  -   cHAT-O-tOP uSER sTATiSTiCS bY aVERAGE   %s-  - -- --- ---.\n |C|\n",
  133.                                 " %s|   # Name/Alias           Location/Group          Time      Chats   Avg  %s|\n |C|\n",
  134.                                 " %s|%4ld %-20.20s %-19.19s  %2ldd %2ldh %2ldm  %5ld  %2ld:%2ld %s|\n",
  135.                                 " %s:-------------------------------------------------------------------------:\n | Overall avg.: %2ld:%2ld  Total time:%3ldd %2ldh %2ldm  (c) 1995 by KiLLraVeN/MST %s|\n `-------------------------------------------------------------------------'\n" };
  136.  
  137.     /* Error reports */
  138.     BYTE    nomemory[]       = "Not enough memory.\n";
  139.     BYTE    nofile[]         = "Could not open: \"%s\".\n";
  140.     BYTE  INCORRECT_ARGS[] = "Incorrect arguments.\n";
  141.  
  142.     ULONG        parameters[ TEMPLATE_SIZE ];
  143.     ULONG        fsize;                /* file size */
  144.     ULONG        ct_entries = 0,    /* Entries in chat-o-top.data */
  145.                 ud_entries = 0;    /* Entries in user.data       */
  146.     ULONG        j , tot_time = 0 , tot_chat = 0;
  147.     register ULONG    i;
  148.  
  149.     int        days , hours , mins , avgm , avgs ;
  150.  
  151.     /* If we have no dos.library we'll exit quietly */
  152.     if ( ! DOSBase )
  153.         Exit( 100 );
  154.  
  155.     /* Set default values */
  156.     for ( i = 0 ; i < TEMPLATE_SIZE ; i++ )
  157.         parameters[ i ] = defaults[ i ];
  158.  
  159.     /* Initialise the list */
  160.     ut_List.mlh_Head     = (struct MinNode *) &ut_List.mlh_Tail;
  161.     ut_List.mlh_Tail     = 0;
  162.     ut_List.mlh_TailPred = (struct MinNode *) &ut_List.mlh_Head;
  163.  
  164.     /* Get the user's args */
  165.     rdargs = ReadArgs( (STRPTR) TEMPLATE, (LONG *) parameters, NULL );
  166.  
  167.     /* Only continue if we have good args */
  168.     if ( ! rdargs )
  169.     {
  170.         Printf( INCORRECT_ARGS );
  171.         MyExit( DOSBase , userdata , ct_ptr , rdargs , ( struct List *) &ut_List , 20 );
  172.     }
  173.  
  174.     /* If there is a SORT method given, check it's validity */
  175.     if ( *((ULONG *) parameters[ SORT ] ) > 2 )
  176.     {
  177.         Printf( "\nValid SORT arguments range from 0 to 2.\n\n" );
  178.         MyExit( DOSBase , userdata , ct_ptr , rdargs , ( struct List *) &ut_List , 20 );
  179.     }
  180.  
  181.     /* Lock User.Data data file and get it's size */
  182.     if ( fsize = GetFileSize( DOSBase , (STRPTR) parameters[ USERDATA ] ) )
  183.         ud_entries = fsize / sizeof( struct USER );
  184.     else
  185.         MyExit( DOSBase , userdata , ct_ptr , rdargs , ( struct List *) &ut_List , 20 );
  186.  
  187.     /* Lock Chat-O-Top.Data file and get it's size */
  188.     if ( fsize = GetFileSize( DOSBase , (STRPTR) parameters[ DATAFILE ] ) )
  189.         ct_entries = fsize / sizeof( struct CHATTOP );
  190.     else
  191.         MyExit( DOSBase , userdata , ct_ptr , rdargs , ( struct List *) &ut_List , 20 );
  192.  
  193.     /* If there are more entries in the Chat-O-Top data file then there
  194.      * are in the User.Data, we will only check the Chat-O-Top data file
  195.      * for the number of entries in the User.Data
  196.      */
  197.     if ( ud_entries < ct_entries )
  198.         ct_entries = ud_entries;
  199.  
  200.     /* We will read the entire user.data in memory to speed it up
  201.      * a whole bit!
  202.      */
  203.     if ( userdata = (struct USER *) AllocVec( ud_entries * sizeof( struct USER ) , MEMF_PUBLIC|MEMF_CLEAR ) )
  204.     {
  205.         fh = Open( (STRPTR) parameters[ USERDATA ] , MODE_OLDFILE );
  206.         if ( ! fh )
  207.         {
  208.             Printf( nofile , (STRPTR) parameters[ USERDATA ] );
  209.             MyExit( DOSBase , userdata , ct_ptr , rdargs , ( struct List *) &ut_List , 20 );
  210.         }
  211.         else
  212.         {
  213.             Read( fh , userdata , ud_entries * sizeof( struct USER ) );
  214.             Close( fh );
  215.         }
  216.     }
  217.     else
  218.     {
  219.         Printf( nomemory );
  220.         MyExit( DOSBase , userdata , ct_ptr , rdargs , ( struct List *) &ut_List , 20 );
  221.     }
  222.  
  223.     /* We will NOT read the entire Chat-O-Top.Data in memory because
  224.      * the time difference will not be that big and the executable
  225.      * will most likely be bigger.
  226.      */
  227.     fh = Open( (STRPTR) parameters[ DATAFILE ] , MODE_OLDFILE );
  228.       if ( ! fh )
  229.     {
  230.         Printf( nofile , (STRPTR) parameters[ DATAFILE ] );
  231.         MyExit( DOSBase , userdata , ct_ptr , rdargs , ( struct List *) &ut_List , 20 );
  232.     }
  233.  
  234.     /* Allocate memory */
  235.     ct_ptr = AllocVec( sizeof( struct CHATTOP ) , MEMF_PUBLIC|MEMF_CLEAR );
  236.     if ( ct_ptr == NULL )
  237.     {
  238.         Printf( nomemory );
  239.         MyExit( DOSBase , userdata , ct_ptr , rdargs , ( struct List *) &ut_List , 20 );
  240.     }
  241.  
  242.     /* Add 3 dummy nodes to avoid problems with the sort-routine
  243.      * This is a flaw in the sort-routine, but this solves the 
  244.      * problem real simple and I don't have to write a new, better,
  245.      * complex and probably bigger sort-routine.
  246.      */
  247.     for ( i = 0 ; i < 3 ; i ++ )
  248.     {
  249.         if ( ut_Node = AllocVec( sizeof( struct USERTOP ) , MEMF_PUBLIC|MEMF_CLEAR ) )
  250.         {
  251.             if ( parameters[ REVERSED ] )
  252.             {
  253.                 ut_Node->ut_Time  = 234567890;
  254.                 ut_Node->ut_Chats = 223456790;
  255.                 ut_Node->ut_Avg    = 223456790;
  256.             }
  257.             AddTail( (struct List *) &ut_List , ( struct Node *) ut_Node );
  258.         }
  259.         else
  260.         {
  261.             Printf( nomemory );
  262.             MyExit( DOSBase , userdata , ct_ptr , rdargs , ( struct List *) &ut_List , 20 );
  263.         }
  264.     }
  265.  
  266.     /* Main loop:
  267.      * ==========
  268.      * 1. Allocate memory for new node
  269.      * 2. Read Chat-O-Top data
  270.      * 3. Read User.Data
  271.      * 4. Add it to the sorted list
  272.      *
  273.      * But with the appropriate checks (if user is still active etc.).
  274.      */
  275.     for ( i = 0 , user_ptr = userdata ; i < ct_entries ; i ++ , user_ptr ++ )
  276.     {
  277.         /* Allocate node */
  278.         if ( ut_Node = AllocVec( sizeof( struct USERTOP ) , MEMF_PUBLIC|MEMF_CLEAR ) )
  279.         {
  280.             j = Read( fh , ct_ptr , sizeof( struct CHATTOP ) );
  281.             if ( j > 0 )
  282.             {
  283.                 if ( ct_ptr->Time != 0 &&
  284.                       ct_ptr->Chats != 0 &&
  285.                       user_ptr->Slot_Number != 0 )
  286.                 {
  287.                     strcpy( ut_Node->ut_Name , user_ptr->Name );
  288.                     strcpy( ut_Node->ut_Location , user_ptr->Location );
  289.                     ut_Node->ut_Time  = ct_ptr->Time;
  290.                     ut_Node->ut_Chats = ct_ptr->Chats;
  291.                     ut_Node->ut_Avg   = ut_Node->ut_Time / ut_Node->ut_Chats;
  292.                     tot_time += ct_ptr->Time;
  293.                     tot_chat += ct_ptr->Chats;
  294.  
  295.                     if ( TRUE == ( MeetMinimum( ut_Node , *((ULONG *) parameters[ MIN ] ) , *((ULONG *) parameters[ SORT ] ) ) ) )
  296.                     {
  297.                         PutInSortedList( (struct List *) &ut_List ,
  298.                                               ut_Node ,
  299.                                               parameters[ REVERSED ] ,
  300.                                               *((ULONG *) parameters[ SORT ] ) );
  301.                     }
  302.                     else
  303.                         FreeVec( ut_Node );
  304.                 }
  305.                 else
  306.                     FreeVec( ut_Node );
  307.             }
  308.             else
  309.             {
  310.                 FreeVec( ut_Node );
  311.                 break;
  312.             }
  313.         }
  314.         else
  315.         {
  316.             Printf( nomemory );
  317.             MyExit( DOSBase , userdata , ct_ptr , rdargs , ( struct List *) &ut_List , 20 );
  318.         }
  319.     }
  320.  
  321.     /* We are done reading and sorting the data, so we can close the file
  322.      * and give back the memory.
  323.      */
  324.     Close( fh );
  325.     FreeVec( userdata );
  326.     userdata = NULL;
  327.  
  328.     /* Remove the three dummy nodes that were put in the list to
  329.      * solve a flaw in the sorting routine. The three last nodes
  330.      * in the list are always the dummy ones.
  331.      */
  332.     for ( i = 0 ; i < 3 ; i ++ )
  333.     {
  334.         ut_Worknode = ( struct USERTOP *) ut_List.mlh_TailPred;
  335.         Remove( ( struct Node *) ut_Worknode );
  336.         FreeVec( ut_Worknode );
  337.     }
  338.  
  339.     /* By default we will put a CLS code in the file we create, but if the
  340.      * user has set the NO_CLS flag, we will NOT do this. We do however
  341.      * open the file, because this will also initialize a new, empty
  342.      * file. If we don't do this, we either have to delete any old
  343.      * file otherwise the data will be stuck after any existing file.
  344.      */
  345.     if ( fh = Open( (STRPTR) parameters[ TO_FILE ] , MODE_NEWFILE ) )
  346.     {
  347.         if ( ! parameters[ NO_CLS ] )
  348.             Write ( fh , "\014" , 1 );
  349.         Close( fh );
  350.     }
  351.     else
  352.     {
  353.         Printf( "Cannot open output file.\n" );
  354.         MyExit( DOSBase , userdata , ct_ptr , rdargs , ( struct List *) &ut_List , 20 );
  355.     }
  356.  
  357.     /* If the user has specified his own header, we will simply copy
  358.      * the specified file and stick our data behind it. If not, we will
  359.      * generate a very simple header.
  360.      */
  361.  
  362.     /* Our very own copy routine :-) */
  363.     if ( ! parameters[ NO_HEAD ] )
  364.     {
  365.         if ( fsize = GetFileSize( DOSBase , (STRPTR) parameters[ HEADER ] ) )
  366.         {
  367.             if ( buffer = AllocVec( fsize , MEMF_CLEAR|MEMF_PUBLIC ) )
  368.             {
  369.                 if ( fh = Open( (STRPTR) parameters[ HEADER ] , MODE_OLDFILE ) )
  370.                 {
  371.                     Read( fh , buffer , fsize );
  372.                     Close( fh );
  373.                     if ( fh = Open( (STRPTR) parameters[ TO_FILE ] , MODE_READWRITE ) )
  374.                     {
  375.                         Seek( fh , 0 , OFFSET_END );
  376.                         Write( fh , buffer , fsize );
  377.                         Close( fh );
  378.                     }
  379.                 }
  380.                 else
  381.                 {
  382.                     Printf( nofile , (STRPTR) parameters[ TO_FILE ] );
  383.                     MyExit( DOSBase , userdata , ct_ptr , rdargs , ( struct List *) &ut_List , 20 );
  384.                 }
  385.                 FreeVec( buffer );
  386.             }
  387.             else
  388.             {
  389.                 Printf( nomemory );
  390.                 MyExit( DOSBase , userdata , ct_ptr , rdargs , ( struct List *) &ut_List , 20 );
  391.             }
  392.         }
  393.         else
  394.             MyExit( DOSBase , userdata , ct_ptr , rdargs , ( struct List *) &ut_List , 20 );
  395.     }
  396.     else
  397.     {
  398.         if ( fh = Open( (STRPTR) parameters[ TO_FILE ] , MODE_READWRITE ) )
  399.         {
  400.             Seek( fh , 0 , OFFSET_END );
  401.             myprintf( temp , headers[ *((ULONG *) parameters[ SORT ] ) ] , (STRPTR) parameters[ BORDER ] , (STRPTR) parameters[ BORDER ] );
  402.             Write( fh , temp , strlen( temp ) );
  403.             Close( fh );
  404.         }
  405.         else
  406.         {
  407.             Printf( nofile , (STRPTR) parameters[ TO_FILE ] );
  408.             MyExit( DOSBase , userdata , ct_ptr , rdargs , ( struct List *) &ut_List , 20 );
  409.         }
  410.     }
  411.     
  412.     /* And now add our data to that header file */
  413.     if ( fh = Open( (STRPTR) parameters[ TO_FILE ] , MODE_READWRITE ) )
  414.     {
  415.         /* Add it to the end of the file */
  416.         Seek( fh , 0 , OFFSET_END );
  417.  
  418.         /* A second header to identify all the data */
  419.         myprintf( temp , headers[ 3 ] , (STRPTR) parameters[ BORDER ] , (STRPTR) parameters[ BORDER ] );
  420.         Write( fh , temp , strlen( temp ) );
  421.  
  422.         /* Add all the user data */
  423.         i = 1;
  424.         ut_Worknode = ( struct USERTOP *) ut_List.mlh_Head;
  425.         while ( ut_Nextnode = ( struct USERTOP *) ut_Worknode->ut_Node.ln_Succ )
  426.         {
  427.             fsize  = ut_Worknode->ut_Time;
  428.             days     = fsize / 86400;
  429.             fsize -= days * 86400;
  430.             hours     = fsize / 3600;
  431.             fsize -= hours * 3600;
  432.             mins     = fsize / 60;
  433.             avgm     = ut_Worknode->ut_Avg / 60;
  434.             avgs   = ut_Worknode->ut_Avg - ( avgm * 60 );
  435.             myprintf( temp , headers[ 4 ] , (STRPTR) parameters[ BORDER ], i,
  436.                                                         ut_Worknode->ut_Name,
  437.                                                         ut_Worknode->ut_Location,
  438.                                                         days, hours , mins,
  439.                                                         ut_Worknode->ut_Chats,
  440.                                                         avgm , avgs ,
  441.                                                         (STRPTR) parameters[ BORDER ] ); 
  442.  
  443.             /* Take care of any spaces (" 1" -> "01" ) */
  444.             for ( j = 0 ; j < 4 ; j ++ )
  445.             {
  446.                 if ( temp[ zeros[ j ] + strlen( (STRPTR) parameters[ BORDER ] ) ] == ' ' )
  447.                     temp[ zeros[ j ] + strlen( (STRPTR) parameters[ BORDER ] ) ] = '0';
  448.             }
  449.  
  450.             Write( fh , temp , strlen( temp ) );
  451.             ut_Worknode = ut_Nextnode;
  452.             i++;
  453.             if ( parameters[ TOP ] != NULL )
  454.             {
  455.                 if ( i > *((ULONG *) parameters[ TOP ] ) )
  456.                     break;
  457.             }
  458.         }
  459.  
  460.         /* And now add the footer */
  461.         fsize  = tot_time;
  462.         days     = fsize / 86400;
  463.         fsize -= days * 86400;
  464.         hours     = fsize / 3600;
  465.         fsize -= hours * 3600;
  466.         mins     = fsize / 60;
  467.         fsize  = tot_time / tot_chat;
  468.         avgm     = fsize / 60;
  469.         avgs   = fsize - ( avgm * 60 );
  470.         myprintf( temp , headers[ 5 ] , (STRPTR) parameters[ BORDER ],
  471.                                                     avgm , avgs , days, hours , mins,
  472.                                                     (STRPTR) parameters[ BORDER ] );
  473.  
  474.         /* Take care of any blanks (fill'm with 0's) */
  475.         for ( j = 4 ; j < 8 ; j ++ )
  476.         {
  477.             if ( temp[ zeros[ j ] + strlen( (STRPTR) parameters[ BORDER ] ) ] == ' ' )
  478.                 temp[ zeros[ j ] + strlen( (STRPTR) parameters[ BORDER ] ) ] = '0';
  479.         }
  480.  
  481.         /* And write it */
  482.         Write( fh , temp , strlen( temp ) );
  483.  
  484.         /* Close the file when you're done */
  485.         Close( fh );
  486.     }
  487.     MyExit( DOSBase , userdata , ct_ptr , rdargs , ( struct List *) &ut_List , 0 );
  488. }
  489.  
  490. void FreeNodes (struct List *list)
  491. {
  492.     struct Node *worknode;
  493.     struct Node *nextnode;
  494.  
  495.     worknode = (struct Node *) list->lh_Head; // First node in list
  496.     while (nextnode = (struct Node *) worknode->ln_Succ)
  497.     {
  498.         Remove( worknode );     // Take the node out of the list
  499.         FreeVec( worknode );      // Free the memory of the node
  500.         worknode = nextnode;      // Go to next node
  501.     }
  502. }
  503.  
  504. ULONG GetFileSize( struct Library *DOSBase , char *filename )
  505. {
  506.     BPTR        fh;
  507.     ULONG        fsize = 0;
  508.     struct    FileInfoBlock     *FBlock;
  509.  
  510.     if ( ( fh = Lock( filename , ACCESS_READ ) ) != NULL )
  511.     {
  512.         if ( ( FBlock = ( struct FileInfoBlock *) AllocDosObject ( DOS_FIB , NULL ) ) )
  513.         {
  514.             if ( Examine( fh , FBlock ) )
  515.                 fsize = FBlock->fib_Size;
  516.             FreeDosObject( DOS_FIB , FBlock );
  517.         }
  518.         UnLock( fh );
  519.     }
  520.     else
  521.         Printf( "Could not lock file: %s\n." , filename );
  522.     return( fsize );
  523. }
  524.  
  525. VOID MyExit( struct Library *DOSBase , struct USER *userdata , struct CHATTOP *ct_ptr , struct RDArgs *rdargs , struct List *list , int rc )
  526. {
  527.     if ( userdata )
  528.         FreeVec( userdata );
  529.  
  530.     if ( ct_ptr )
  531.         FreeVec( ct_ptr );
  532.  
  533.     FreeNodes( list );
  534.  
  535.     if ( rdargs )
  536.         FreeArgs( rdargs );
  537.  
  538.     if ( DOSBase )
  539.         CloseLibrary( DOSBase );
  540.  
  541.     Exit( rc );
  542. }
  543.  
  544. VOID myprintf( char *output , char *ctl, ...)
  545. {
  546.    long *arg1;
  547.  
  548.    arg1 = (long *)(&ctl + 1);
  549.    RawDoFmt(ctl, arg1, (void (*))"\x16\xc0\x4e\x75", output );
  550. }
  551.  
  552. VOID PutInSortedList( struct List *list , struct USERTOP *ut_Node , ULONG ReverseSort , ULONG SortBy )
  553. {
  554.     struct    USERTOP    *ut_Worknode, *ut_Nextnode;
  555.     BOOL        inserted = FALSE, breakit = FALSE;
  556.  
  557.     /* If ReverseSort is TRUE, we will put the node in a list that will
  558.      * be sorted from LOW to HIGH. Otherwise it will be put in a list that
  559.      * that is sorted from HIGH to LOW.
  560.      */
  561.     if ( FALSE == ReverseSort )
  562.     {
  563.         /* Find the first node that is BIGGER than the number
  564.          * of chats/time we've got and insert it after that
  565.          * node. This way we will get a sorted list from HIGHEST
  566.          * to LOWEST.
  567.          */
  568.         ut_Worknode = ( struct USERTOP *) list->lh_TailPred;
  569.         while ( ut_Nextnode = ( struct USERTOP *) ut_Worknode->ut_Node.ln_Pred )
  570.         {
  571.             switch( SortBy )
  572.             {
  573.                 case NULL:    /* Sort by Time */
  574.                     if ( ut_Worknode->ut_Time >= ut_Node->ut_Time )
  575.                     {
  576.                         Insert( list , ( struct Node *) ut_Node , ( struct Node *) ut_Worknode );
  577.                         inserted = TRUE;
  578.                         breakit  = TRUE;
  579.                     }
  580.                     break;
  581.  
  582.                 case 1   : /* Sort by Chats */
  583.                     if ( ut_Worknode->ut_Chats >= ut_Node->ut_Chats )
  584.                     {
  585.                         Insert( list , ( struct Node *) ut_Node , ( struct Node *) ut_Worknode );
  586.                         inserted = TRUE;
  587.                         breakit  = TRUE;
  588.                     }
  589.                     break;
  590.  
  591.                 case 2    : /* Sort by Avg */
  592.                     if ( ut_Worknode->ut_Avg >= ut_Node->ut_Avg )
  593.                     {
  594.                         Insert( list , ( struct Node *) ut_Node , ( struct Node *) ut_Worknode );
  595.                         inserted = TRUE;
  596.                         breakit  = TRUE;
  597.                     }
  598.                     break;
  599.             }
  600.             ut_Worknode = ut_Nextnode;
  601.             if ( TRUE == breakit )
  602.                 break;
  603.         }
  604.         if ( FALSE == inserted )
  605.             Insert( list , ( struct Node *) ut_Node , NULL );
  606.     }
  607.     else
  608.     {
  609.         ut_Worknode = ( struct USERTOP *) list->lh_Head;
  610.         while ( ut_Nextnode = ( struct USERTOP *) ut_Worknode->ut_Node.ln_Succ )
  611.         {
  612.             switch( SortBy )
  613.             {
  614.                 case NULL:    /* Sort by Time */
  615.                     if ( ut_Worknode->ut_Time >= ut_Node->ut_Time )
  616.                     {
  617.                         ut_Nextnode = ( struct USERTOP *) ut_Worknode->ut_Node.ln_Pred;
  618.                         Insert( list , ( struct Node *) ut_Node , ( struct Node *) ut_Nextnode );
  619.                         inserted = TRUE;
  620.                         breakit  = TRUE;
  621.                     }
  622.                     break;
  623.  
  624.                 case 1   : /* Sort by Chats */
  625.                     if ( ut_Worknode->ut_Chats >= ut_Node->ut_Chats )
  626.                     {
  627.                         ut_Nextnode = ( struct USERTOP *) ut_Worknode->ut_Node.ln_Pred;
  628.                         Insert( list , ( struct Node *) ut_Node , ( struct Node *) ut_Nextnode );
  629.                         inserted = TRUE;
  630.                         breakit  = TRUE;
  631.                     }
  632.                     break;
  633.  
  634.                 case 2    : /* Sort by Avg */
  635.                     if ( ut_Worknode->ut_Avg >= ut_Node->ut_Avg )
  636.                     {
  637.                         ut_Nextnode = ( struct USERTOP *) ut_Worknode->ut_Node.ln_Pred;
  638.                         Insert( list , ( struct Node *) ut_Node , ( struct Node *) ut_Nextnode );
  639.                         inserted = TRUE;
  640.                         breakit  = TRUE;
  641.                     }
  642.                     break;
  643.             }
  644.             ut_Worknode = ut_Nextnode;
  645.             if ( TRUE == breakit )
  646.                 break;
  647.         }
  648.         if ( FALSE == inserted )
  649.             AddTail( list , ( struct Node *) ut_Node );
  650.     }
  651. }
  652.  
  653. BOOL MeetMinimum( struct USERTOP *ut_Node , ULONG Minimum , ULONG SortBy )
  654. {
  655.     if ( NULL == Minimum )
  656.         return( TRUE );
  657.  
  658.     switch( SortBy )
  659.     {
  660.         case    NULL:    /* Time */
  661.             if ( Minimum <= ut_Node->ut_Time )
  662.                 return( TRUE );
  663.             else
  664.                 return( FALSE );
  665.  
  666.         case    1    :    /* Chats */
  667.             if ( Minimum <= ut_Node->ut_Chats )
  668.                 return( TRUE );
  669.             else
  670.                 return( FALSE );
  671.  
  672.         case    2    :    /* Average */
  673.             if ( Minimum <= ut_Node->ut_Avg )
  674.                 return( TRUE );
  675.             else
  676.                 return( FALSE );
  677.     }
  678. }
  679.